package org.idea.qiyu.framework.rocketmq.config.producer;

import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MQProducer;
import org.idea.qiyu.framework.rocketmq.annotation.QiyuProducer;
import org.idea.qiyu.framework.rocketmq.config.excpetion.MQException;
import org.idea.qiyu.framework.rocketmq.config.serializer.Serializer;
import org.idea.qiyu.framework.rocketmq.properties.RocketMqProducerProperties;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.Field;

/**
 * @Author linhao
 * @Date created in 9:16 上午 2021/7/1
 */
public class MqProducerFactory implements IMQProducerFactory, ApplicationContextAware, DisposableBean, BeanPostProcessor {

    private MQProducer mqProducer;
    private RocketMqProducerProperties rocketMqProducerProperties;
    private ApplicationContext applicationContext;
    private String nameServers;
    private String groupName;

    public MqProducerFactory(String nameServers, String groupName) {
        this.nameServers = nameServers;
        this.groupName = groupName;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class clazz = AopUtils.isAopProxy(bean) ? AopUtils.getTargetClass(bean) : bean.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(QiyuProducer.class)) {
                QiyuProducer qiyuProducer = field.getAnnotation(QiyuProducer.class);
                String topic = qiyuProducer.topic();
                Object serializer = null;
                try {
                    serializer = qiyuProducer.serializer().newInstance();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                MqProducerTemplate mqProducerTemplate = new MqProducerTemplate();
                mqProducerTemplate.setProducerFactory(this);
                mqProducerTemplate.setTopic(topic);
                mqProducerTemplate.setSerializer((Serializer) serializer);
                mqProducerTemplate.setTag(qiyuProducer.tag());
                try {
                    field.set(bean, mqProducerTemplate);
                    //如果是在aop内部引入
                    if(AopUtils.isAopProxy(bean) && bean instanceof Advised) {
                        Advised advised = (Advised) bean;
                        Object originBean = advised.getTargetSource().getTarget();
                        field.set(originBean,originBean);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }


    @Override
    public MQProducer createMQProducer() {
        if (mqProducer == null) {
            DefaultMQProducer defaultMQProducer = new DefaultMQProducer(rocketMqProducerProperties.getGroupName());
            defaultMQProducer.setNamesrvAddr(rocketMqProducerProperties.getNameSrv());
            defaultMQProducer.setSendMsgTimeout(rocketMqProducerProperties.getSendMsgTimeout());
            defaultMQProducer.setVipChannelEnabled(false);
            try {
                mqProducer = defaultMQProducer;
                mqProducer.start();
            } catch (MQClientException e) {
                throw new MQException(e);
            }
        }
        return mqProducer;
    }


    @Override
    public void destroy() throws Exception {

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        this.rocketMqProducerProperties = applicationContext.getBean(RocketMqProducerProperties.class);
    }
}
